/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.awt;
import java.awt.event.*;
import java.io.*;
import java.util.Iterator;
import java.text.MessageFormat;
import javax.swing.*;
import org.openide.TopManager;
import org.openide.NotifyDescriptor;
import org.openide.loaders.*;
import org.openide.cookies.InstanceCookie;
import org.openide.nodes.*;
import org.openide.util.actions.Presenter;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.WeakListener;
/** An extended version of swing's JMenuBar. This menubar can
* load its content from the folder where its "disk image" is stored.<P>
* Moreover, menu is <code>Externalizable</code> to restore its persistent
* state with minimal storage expensiveness.
*
* @version 1.0
* @author David Peroutka, Dafe Simonek
*/
public class MenuBar extends JMenuBar implements Externalizable {
/** the folder which represents and loads content of the menubar */
private MenuBarFolder menuBarFolder;
static final long serialVersionUID =-4721949937356581268L;
/** Don't call this constructor or this class will not get
* initialized properly. This constructor is only for externalization.
*/
public MenuBar() {
super();
}
/** Creates a new <code>MenuBar</code> from given folder.
* @param folder The folder from which to create the content of the menubar.
* If the parameter is null, default menu folder is obtained.
*/
public MenuBar(DataFolder folder) {
super();
// PENDING(david) -- setBorder(new MenuBorder());
startLoading((folder == null)
? TopManager.getDefault().getPlaces().folders().menus()
: folder);
}
/** Blocks until the menubar is completely created. */
public void waitFinished () {
menuBarFolder.instanceFinished();
}
/** Saves the contents of this object to the specified stream.
*
* @exception IOException Includes any I/O exceptions that may occur
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(menuBarFolder.getFolder());
}
/**
* Restores contents of this object from the specified stream.
*
* @exception ClassNotFoundException If the class for an object being
* restored cannot be found.
*/
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
startLoading((DataFolder)in.readObject());
}
/** Starts loading of this menu from menu folder */
void startLoading (final DataFolder folder) {
menuBarFolder = new MenuBarFolder(folder, this);
}
/** This class can be used to fill the content of given
* <code>MenuBar</code> from the given <code>DataFolder</code>.
*/
static final class MenuBarFolder extends FolderInstance {
/** Asociated menubar which we should fill */
MenuBar menuBar;
/** Creates a new menubar folder on the specified <code>DataFolder</code>.
* @param folder a <code>DataFolder</code> to work with
*/
public MenuBarFolder (final DataFolder folder, final MenuBar menuBar) {
super(folder);
this.menuBar = menuBar;
recreate ();
}
/** Full name of the data folder's primary file separated by dots.
* @return the name
*/
public String instanceName () {
return menuBar.getClass().getName();
}
/** Returns the root class of all objects.
* @return MenuBar.class
*/
public Class instanceClass ()
throws java.io.IOException, ClassNotFoundException {
return MenuBar.class;
}
/** Accepts only cookies that can provide <code>MenuBar</code>.
* @param cookie the instance cookie to test
* @return true if the cookie can provide <code>MenuBar</code>
*/
protected InstanceCookie acceptCookie (InstanceCookie cookie)
throws java.io.IOException,
ClassNotFoundException {
return MenuBar.class.isAssignableFrom(cookie.instanceClass())
? cookie : null;
}
/** Returns a <code>MenuFolder</code> cookie for the specified
* <code>DataFolder</code>.
* @param df a <code>DataFolder</code> to create the cookie for
* @return a <code>MenuFolder</code> for the specified folder
*/
protected InstanceCookie acceptFolder (DataFolder df) {
return new MenuFolder(df);
}
/** Updates the <code>MenuBar</code> represented by this folder.
*
* @param cookies array of instance cookies for the folder
* @return the updated <code>MenuBar</code> representee
*/
protected Object createInstance (InstanceCookie[] cookies)
throws java.io.IOException, ClassNotFoundException {
// System.out.println ("Creating menu bar:" + menuBar); // NOI18N
// clear old content
menuBar.removeAll();
// fill with new content
for (int i = 0; i < cookies.length; i++) {
try {
Object obj = cookies[i].instanceCreate();
if (obj instanceof JMenu) {
menuBar.add((JMenu)obj);
}
} catch (Exception exc) {
TopManager.getDefault().notifyException(exc);
/* new NotifyDescriptor.Exception(exc,
NbBundle.getBundle(this).getString("EXC_LoadMenu")));*/
}
}
final MenuBar menuBarRef = menuBar;
SwingUtilities.invokeLater(new Runnable() {
public void run () {
menuBarRef.validate();
menuBarRef.repaint();
}
});
return menuBar;
}
/** For outer class access to the data folder */
DataFolder getFolder () {
return folder;
}
}
/** This class can be used to produce a <code>JMenu</code> instance
* from the given <code>DataFolder</code>.
*/
static final class MenuFolder extends FolderInstance
implements NodeListener {
/** the <code>JMenu</code> to work with */
private JMenu menu;
/**
* Creates a menu on the specified <code>DataFolder</code>.
* @param folder a <code>DataFolder</code> to work with
*/
public MenuFolder (final DataFolder folder) {
super(folder);
recreate ();
}
/**
* Returns a <code>Menu</code> representee of this folder.
* @return a <code>Menu</code> representee of this folder
*/
public final JMenu getMenu() {
if (menu == null) {
menu = new org.openide.awt.JMenuPlus(
folder.getNodeDelegate ().getDisplayName ()
);
folder.getNodeDelegate ().addNodeListener (
WeakListener.node (this, folder.getNodeDelegate ())
);
}
return menu;
}
/** If the display name changes, than change the name of the menu.
*/
public void propertyChange (java.beans.PropertyChangeEvent ev) {
if (
Node.PROP_DISPLAY_NAME.equals (ev.getPropertyName ()) ||
Node.PROP_NAME.equals (ev.getPropertyName ())
) {
String name = folder.getNodeDelegate ().getDisplayName ();
getMenu ().setText (name);
}
}
/** Fired when a set of new children is added.
* @param ev event describing the action
*/
public void childrenAdded (NodeMemberEvent ev) {
}
/** Fired when a set of children is removed.
* @param ev event describing the action
*/
public void childrenRemoved (NodeMemberEvent ev) {
}
/** Fired when the order of children is changed.
* @param ev event describing the change
*/
public void childrenReordered(NodeReorderEvent ev) {
}
/** Fired when the node is deleted.
* @param ev event describing the node
*/
public void nodeDestroyed (NodeEvent ev) {
}
/** The name of the menu
* @return the name
*/
public String instanceName () {
return getMenu().getClass().getName();
}
/** Returns the class of represented menu.
* @return Object.class
*/
public Class instanceClass ()
throws java.io.IOException, ClassNotFoundException {
return JMenu.class;
}
/** If no instance cookie, tries to create execution action on the
* data object.
*/
protected InstanceCookie acceptDataObject (DataObject dob) {
InstanceCookie ic = super.acceptDataObject (dob);
if (ic == null) {
return new InstanceSupport.Instance (ExecBridge.createMenuItem (dob));
} else {
return ic;
}
}
/**
* Accepts only cookies that can provide <code>Menu</code>.
* @param cookie an <code>InstanceCookie</code> to test
* @return true if the cookie can provide accepted instances
*/
protected InstanceCookie acceptCookie(InstanceCookie cookie)
throws java.io.IOException,
ClassNotFoundException {
Class c = cookie.instanceClass();
return ((Presenter.Menu.class.isAssignableFrom(c)) ||
(JMenuItem.class.isAssignableFrom(c)) ||
(JSeparator.class.isAssignableFrom(c))) ? cookie : null;
}
/**
* Returns a <code>Menu.Folder</code> cookie for the specified
* <code>DataFolder</code>.
* @param df a <code>DataFolder</code> to create the cookie for
* @return a <code>Menu.Folder</code> for the specified folder
*/
protected InstanceCookie acceptFolder(DataFolder df) {
return new MenuFolder(df);
}
/** Updates the <code>JMenu</code> represented by this folder.
* @param cookies array of instance cookies for the folder
* @return the updated <code>JMenu</code> representee
*/
protected Object createInstance(InstanceCookie[] cookies)
throws java.io.IOException, ClassNotFoundException {
// clear first - refresh the menu's content
getMenu().removeAll();
for (int i = 0; i < cookies.length; i++) {
try {
Object obj = cookies[i].instanceCreate();
if (obj instanceof Presenter.Menu) {
obj = ((Presenter.Menu)obj).getMenuPresenter();
}
if (obj instanceof JMenuItem) {
menu.add((JMenuItem)obj);
} else {
if (obj instanceof JSeparator) {
menu.addSeparator();
}
}
} catch (Exception exc) {
TopManager.getDefault().notifyException(exc
/* new NotifyDescriptor.Exception(exc,
MessageFormat.format(
NbBundle.getBundle(this).getString("EXC_LoadMenuItem"),
new Object[] { cookies[i].instanceName() }
)
) */
);
}
}
menu.setEnabled((cookies.length == 0) ? false : true);
// request menu repaint
if (cookies.length > 0) {
JPopupMenu popup = menu.getPopupMenu();
popup.pack();
popup.repaint();
}
// Special help ID dependent on name of menu, since otherwise
// there would be no way to configure the ID from the DataFolder.
HelpCtx.setHelpIDString (menu, MenuFolder.class.getName () + "." + menu.getText ()); // NOI18N
return menu;
}
}
}
/*
* Log
* 17 dperoutka-src-gandalf1.16 1/20/00 Jaroslav Tulach Menu on multiuser
* instalation can be renamed.
* 16 dperoutka-src-gandalf1.15 1/13/00 Ian Formanek NOI18N
* 15 dperoutka-src-gandalf1.14 1/13/00 Jaroslav Tulach File names can be
* localized.
* 14 dperoutka-src-gandalf1.13 1/12/00 Ian Formanek NOI18N
* 13 dperoutka-src-gandalf1.12 11/5/99 Jesse Glick Context help jumbo
* patch.
* 12 dperoutka-src-gandalf1.11 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 11 dperoutka-src-gandalf1.10 8/9/99 Ian Formanek Generated Serial Version
* UID
* 10 dperoutka-src-gandalf1.9 6/28/99 Ian Formanek NbJMenu renamed to
* JMenuPlus
* 9 dperoutka-src-gandalf1.8 6/28/99 Ian Formanek Fixed bug 2043 - It is
* virtually impossible to choose lower items of New From Template from
* popup menu on 1024x768
* 8 dperoutka-src-gandalf1.7 6/9/99 Jaroslav Tulach Executables can be in
* menu & toolbars.
* 7 dperoutka-src-gandalf1.6 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 6 dperoutka-src-gandalf1.5 3/30/99 Ian Formanek FolderInstance creation
* in single thread
* 5 dperoutka-src-gandalf1.4 3/2/99 David Simonek icons repair
* 4 dperoutka-src-gandalf1.3 2/26/99 David Simonek
* 3 dperoutka-src-gandalf1.2 2/19/99 David Simonek menu related changes...
* 2 dperoutka-src-gandalf1.1 1/25/99 David Peroutka
* 1 dperoutka-src-gandalf1.0 1/25/99 David Peroutka
* $
*/